#include "RingQueue.hpp"
#include <pthread.h>
#include <unistd.h>
#include <ctime>
#include "Task.hpp"

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

class ThreadData
{
public:
    RingQueue<Task> *rq;
    string name;
};

void *Productor(void *args)
{
    // 1.有数据
    ThreadData *td = static_cast<ThreadData *>(args);
    while (true)
    {
        int data1 = rand() % 10; //[0, 9]
        int data2 = rand() % 10; //[0, 9]
        char op = opers[rand() % opers.size()];

        // 2.生产
        Task t(data1, data2, op);
        td->rq->Push(t);
        pthread_mutex_lock(&mutex);
        cout << "Thread name: " << td->name << ", productor data : " << t.PrintTask() << endl;
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
}

void *Consumer(void *args)
{
    ThreadData *td = static_cast<ThreadData *>(args);
    // 2.处理任务
    while (true)
    {
        // 1.消费数据
        Task t;
        td->rq->Pop(&t);
        // 2.对数据做处理
        t.Run();
        pthread_mutex_lock(&mutex);
        cout << "Thread name: " << td->name <<  ", consumer data: " << t.PrintResult() << endl;
        pthread_mutex_unlock(&mutex);
    }
}

int main()
{
    srand((uint64_t)time(nullptr) ^ getpid());
    RingQueue<Task> *rq = new RingQueue<Task>();
    pthread_t c[2], p[3];

    ThreadData *td1 = new ThreadData();
    td1->rq = rq;
    td1->name = "thread-1";
    pthread_create(&p[0], nullptr, Productor, td1);

    ThreadData *td2 = new ThreadData();
    td2->rq = rq;
    td2->name = "thread-2";
    pthread_create(&p[1], nullptr, Productor, td2);

    ThreadData *td3 = new ThreadData();
    td3->rq = rq;
    td3->name = "thread-3";
    pthread_create(&p[2], nullptr, Productor, td3);

    ThreadData *td4 = new ThreadData();
    td4->rq = rq;
    td4->name = "thread-4";
    pthread_create(&c[0], nullptr, Consumer, td4);
    
    ThreadData *td5 = new ThreadData();
    td5->rq = rq;
    td5->name = "thread-5";
    pthread_create(&c[1], nullptr, Consumer, td5);


    pthread_join(p[0], nullptr);
    pthread_join(p[1], nullptr);
    pthread_join(p[2], nullptr);
    pthread_join(c[0], nullptr);
    pthread_join(c[1], nullptr);
    return 0;
}